package com.yiren.dbaa.net;

import android.app.Activity;
import android.content.Context;
import android.util.Base64;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.yiren.backstage.config.api.LoadConfigApi;
import com.yiren.dbaa.net.bean.UrlBean;
import com.yiren.dbaa.net.interf.BeanCallback;
import com.yiren.dbaa.net.interf.FileCallBack;
import com.yiren.dbaa.net.interf.StringCallback;
import com.yiren.dbaa.view.toast.MessageBox;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * @author lwb
 * @date :2021/12/13 10:46
 * @description: 网络请求工具类
 */
public class OkHttpUtils {

    private static final String TAG = "OkHttpUtils";
    public static final int ERROR_CODE_401 = 401;
    private static final MediaType JSON = MediaType.parse("application/json");
    private static OkHttpUtils mInstance;
    private OkHttpClient mOkHttpClient;

    private OkHttpUtils() {
        mOkHttpClient = OKHttpClient.getOKHttpClient();
    }

    public static OkHttpUtils getInstance() {
        if (mInstance == null) {
            synchronized (OkHttpUtils.class) {
                if (mInstance == null) {
                    mInstance = new OkHttpUtils();
                }
            }
        }
        return mInstance;
    }

    /**
     * get请求，异步方式获取返回字符串
     */
    public void getStringByAsync(Context context, UrlBean urlBean, StringCallback callback) {
        Request request = getRequest(context, urlBean);
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ((Activity) context).runOnUiThread(() -> {
                    if (e instanceof UnknownHostException) {
                        MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                    } else {
                        requestFailure(context, urlBean.getDescription(), e);
                    }
                    if (null != callback) {
                        callback.getFail();
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                ((Activity) context).runOnUiThread(() -> {
                    if (response.code() == 200) {
                        if (null != callback) {
                            callback.getString(result);
                        }
                    } else {
                        if (null != callback) {
                            callback.getFail();
                        }
                        if (response.code() == ERROR_CODE_401) {
                            NetworkProcessing.afreshLogin(((Activity) context));
                        } else {
                            responseFailure(context, urlBean.getDescription(), result);
                        }
                    }
                });
            }
        });
    }

    /**
     * get请求，同步方式，直接返回对象
     */
    public <T extends Object> T getBeanBySync(Context context, UrlBean urlBean, Class<T> clazz) {
        Request reuqest = getRequest(context, urlBean);
        try {
            String json = mOkHttpClient.newCall(reuqest).execute().body().string();
            T t = new Gson().fromJson(json, clazz);
            return t;
        } catch (IOException e) {
            ((Activity) context).runOnUiThread(() -> {
                if (e instanceof UnknownHostException) {
                    MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                } else {
                    requestFailure(context, urlBean.getDescription(), e);
                }
            });
            return null;
        }
    }

    /**
     * get请求，异步方式，回调传回对象
     */
    public <T extends Object> void getBeanByAsync(Context context, UrlBean urlBean, Class<T> clazz, BeanCallback<T> callback) {
        Request request = getRequest(context, urlBean);
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ((Activity) context).runOnUiThread(() -> {
                    if (e instanceof UnknownHostException) {
                        MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                    } else {
                        requestFailure(context, urlBean.getDescription(), e);
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                T t = null;
                try {
                    t = new Gson().fromJson(result, clazz);
                } catch (JsonSyntaxException e) {
                    ((Activity) context).runOnUiThread(() -> requestFailure(context, urlBean.getDescription(), e));
                }
                T finalT = t;
                ((Activity) context).runOnUiThread(() -> {
                    if (callback != null && finalT != null) {
                        callback.getBean(finalT);
                    }
                });
            }
        });
    }

    /**
     * post异步请求提交map集合
     */
    public void postMapByAsync(Context context, UrlBean urlBean, Map<String, Object> map, StringCallback callback) {
        // form 表单形式上传
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (map != null) {
            // map 里面是请求中所需要的 key 和 value
            for (Map.Entry entry : map.entrySet()) {
                requestBody.addFormDataPart(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
            }
        }
        Request request = postRequest(context, urlBean, requestBody.build());
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ((Activity) context).runOnUiThread(() -> {
                    if (e instanceof UnknownHostException) {
                        MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                    } else {
                        requestFailure(context, urlBean.getDescription(), e);
                    }
                    if (null != callback) {
                        callback.getFail();
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                ((Activity) context).runOnUiThread(() -> {
                    if (response.code() == 200) {
                        if (null != callback) {
                            callback.getString(result);
                        }
                    } else {
                        if (null != callback) {
                            callback.getFail();
                        }
                        if (response.code() == ERROR_CODE_401) {
                            NetworkProcessing.afreshLogin(((Activity) context));
                        } else {
                            responseFailure(context, urlBean.getDescription(), result);
                        }
                    }
                });
            }
        });
    }

    /**
     * post异步请求提交登录请求
     */
    public void postMapLoginAsync(Context context, UrlBean urlBean, Map<String, Object> map, StringCallback callback) {
        // form 表单形式上传
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (map != null) {
            // map 里面是请求中所需要的 key 和 value
            for (Map.Entry entry : map.entrySet()) {
                requestBody.addFormDataPart(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
            }
        }
        String base64EncodedCredentials = Base64.encodeToString("djapp:e4a27c45-cc86-4651-8e40-164a938921c1".getBytes(), Base64.NO_WRAP);
        Request request = new Request.Builder().url(urlBean.getUrl())
                .header("User-Agent", "OkHttp Headers.java")
                .addHeader("Authorization", "Basic " + base64EncodedCredentials)
                .post(requestBody.build())
                .tag(this)
                .build();
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ((Activity) context).runOnUiThread(() -> {
                    if (e instanceof UnknownHostException) {
                        MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                    } else {
                        requestFailure(context, urlBean.getDescription(), e);
                    }
                    if (null != callback) {
                        callback.getFail();
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                ((Activity) context).runOnUiThread(() -> {
                    if (response.code() == 200) {
                        if (null != callback) {
                            callback.getString(result);
                        }
                    } else {
                        if (null != callback) {
                            callback.getFail();
                        }
                        if (response.code() == ERROR_CODE_401) {
                            NetworkProcessing.afreshLogin(((Activity) context));
                        } else {
                            responseFailure(context, urlBean.getDescription(), result);
                        }
                    }
                });
            }
        });
    }

    public String z(String adress_Http, String strJson) {
        String returnLine = "";
        try {
            URL my_url = new URL(adress_Http);
            HttpURLConnection connection = (HttpURLConnection) my_url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", "application/json");
            connection.connect();
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            byte[] content = strJson.getBytes("utf-8");
            out.write(content, 0, content.length);
            out.flush();
            out.close(); // flush and close
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
            String line = "";
            System.out.println("Contents of post request start");
            while ((line = reader.readLine()) != null) {
                returnLine += line;
                System.out.println(line);
            }
            reader.close();
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnLine;
    }

    /**
     * post异步请求提交json数据
     */
    public void postJsonString(Context context, UrlBean urlBean, String json, StringCallback callback) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        Request request = postRequest(context, urlBean, requestBody);
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ((Activity) context).runOnUiThread(() -> {
                    if (e instanceof UnknownHostException) {
                        MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                    } else {
                        requestFailure(context, urlBean.getDescription(), e);
                    }
                    if (null != callback) {
                        callback.getFail();
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                ((Activity) context).runOnUiThread(() -> {
                    if (response.code() == 200) {
                        if (null != callback) {
                            callback.getString(result);
                        }
                    } else {
                        if (null != callback) {
                            callback.getFail();
                        }
                        if (response.code() == ERROR_CODE_401) {
                            NetworkProcessing.afreshLogin(((Activity) context));
                        } else {
                            responseFailure(context, urlBean.getDescription(), result);
                        }
                    }
                });
            }
        });
    }

    /**
     * post同步请求返回对象
     *
     * @param map 本次请求要上传的请求条件
     * @return 本次请求的结果解析后的变量对象
     */
    public <T extends Object> T postBeanBySync(Context context, UrlBean urlBean, Map<String, String> map, Class<T> claxx) {
        FormBody.Builder fb = new FormBody.Builder();
        //遍历map集合中的所有键值对，将每一组键值对数据天机到fb对象中
        Set<String> keys = map.keySet();
        for (String key : keys) {
            if (map.get(key) == null) {
                continue;
            }
            fb.add(key, map.get(key));
        }
        Request request = postRequest(context, urlBean, fb.build());
        try {
            String json = mOkHttpClient.newCall(request).execute().body().string();
            T t = new Gson().fromJson(json, claxx);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
            ((Activity) context).runOnUiThread(() -> {
                if (e instanceof UnknownHostException) {
                    MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                } else {
                    requestFailure(context, urlBean.getDescription(), e);
                }
            });
            return null;
        }
    }

    /**
     * 异步post请求上传文件
     *
     * @param map       请求参数
     * @param type      上传文件类型key值
     * @param mediaType 文件类型(image/*  video/*  audio/*)
     * @param file      上传文件 file类型
     */
    public void uploadFileByAsync(Context context, UrlBean urlBean, Map<String, Object> map, String type, String mediaType, File file, StringCallback callback) {
        // form 表单形式上传
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (file != null) {
            // MediaType.parse() 里面是上传的文件类型。
            RequestBody body = RequestBody.create(MediaType.parse(mediaType), file);
            // 参数分别为， 请求key ，文件名称 ， RequestBody
            requestBody.addFormDataPart(type, file.getName(), body);
        }
        if (map != null) {
            // map 里面是请求中所需要的 key 和 value
            for (Map.Entry entry : map.entrySet()) {
                requestBody.addFormDataPart(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
            }
        }
        Request request = postRequest(context, urlBean, requestBody.build());
        // readTimeout("请求超时时间" , 时间单位);
        mOkHttpClient.newBuilder().readTimeout(10000, TimeUnit.MILLISECONDS).build().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ((Activity) context).runOnUiThread(() -> {
                    if (e instanceof UnknownHostException) {
                        MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                    } else {
                        requestFailure(context, urlBean.getDescription(), e);
                    }
                    if (null != callback) {
                        callback.getFail();
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String str = response.body().string();
                ((Activity) context).runOnUiThread(() -> {
                    if (callback != null) {
                        callback.getString(str);
                    }
                });
            }
        });
    }

    /**
     * 异步下载文件
     */
    public <T> void downLoadFile(Context context, UrlBean urlBean, String zipPath, FileCallBack callBack) {
        String access_token = LoadConfigApi.loadUserParamConfig(context).getAccessToken();
        final File file = new File(zipPath);
        if (file.exists()) {
            if (callBack != null) {
                callBack.successCallBack(file);
            }
            return;
        } else {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        Request request = new Request.Builder()
                .url(urlBean.getUrl())  //文件url
                .header("User-Agent", "OkHttp Headers.java")
                .addHeader("Authorization", "Bearer " + access_token)
                .addHeader("Accept", "application/json; q=0.5")
                .addHeader("Accept", "application/vnd.github.v3+json")
                .build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ((Activity) context).runOnUiThread(() -> {
                    if (e instanceof UnknownHostException) {
                        MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                    } else {
                        requestFailure(context, urlBean.getDescription(), e);
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                try {
                    long total = response.body().contentLength();
                    Log.e(TAG, "total------>" + total);
                    long current = 0;
                    is = response.body().byteStream();
                    fos = new FileOutputStream(file);
                    while ((len = is.read(buf)) != -1) {
                        current += len;
                        fos.write(buf, 0, len);
                        Log.e(TAG, "current------>" + current);
                    }
                    fos.flush();
                    ((Activity) context).runOnUiThread(() -> {
                        if (callBack != null) {
                            callBack.successCallBack(file);
                        }
                    });
                } catch (IOException e) {
                    Log.e(TAG, e.toString());
                } finally {
                    try {
                        if (is != null) {
                            is.close();
                        }
                        if (fos != null) {
                            fos.close();
                        }
                    } catch (IOException e) {
                        Log.e(TAG, e.toString());
                    }
                }
            }
        });
    }

    /**
     * 异步获取图片流 urlBean.getUrl()为图片路径path
     *
     * @param callBack
     */
    public void getImageStream(Context context, UrlBean urlBean, FileCallBack callBack) {
        String access_token = LoadConfigApi.loadUserParamConfig(context).getAccessToken();
        URL url;
        try {
            url = new URL(urlBean.getUrl());
            Request request = new Request.Builder()
                    .url(url)
                    .header("User-Agent", "OkHttp Headers.java")
                    .addHeader("Authorization", "Bearer " + access_token)
                    .addHeader("Accept", "application/json; q=0.5")
                    .addHeader("Accept", "application/vnd.github.v3+json")
                    .build();
            Call call = mOkHttpClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    ((Activity) context).runOnUiThread(() -> {
                        if (e instanceof UnknownHostException) {
                            MessageBox.show(context, urlBean.getDescription() + ":服务器连接失败，请检查网络连接是否正常！");
                        } else {
                            requestFailure(context, urlBean.getDescription(), e);
                        }
                    });
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    InputStream is = response.body().byteStream();
                    ((Activity) context).runOnUiThread(() -> {
                        if (callBack != null && response.code() == 200) {
                            callBack.successCallBack(is);
                        }
                    });
                }
            });
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取get请求
     */
    private Request getRequest(Context context, UrlBean urlBean) {
        Request request;
        if (urlBean.isAuth()) {
            String access_token = LoadConfigApi.loadUserParamConfig(context).getAccessToken();
            request = new Request.Builder().tag(context).get().url(urlBean.getUrl())
                    .header("User-Agent", "OkHttp Headers.java")
                    .addHeader("Authorization", "Bearer " + access_token)
                    .addHeader("Accept", "application/json; q=0.5")
                    .addHeader("Accept", "application/vnd.github.v3+json")
                    .build();
        } else {
            request = new Request.Builder().tag(context).get().url(urlBean.getUrl())
                    .header("User-Agent", "OkHttp Headers.java")
                    .addHeader("Accept", "application/json; q=0.5")
                    .addHeader("Accept", "application/vnd.github.v3+json")
                    .build();
        }
        return request;
    }

    /**
     * 获取post请求
     */
    private Request postRequest(Context context, UrlBean urlBean, RequestBody body) {
        Request request;
        if (urlBean.isAuth()) {
            String access_token = LoadConfigApi.loadUserParamConfig(context).getAccessToken();
            request = new Request.Builder().url(urlBean.getUrl())
                    .header("User-Agent", "OkHttp Headers.java")
                    .addHeader("Authorization", "Bearer " + access_token)
                    .addHeader("Accept", "application/json; q=0.5")
                    .addHeader("Accept", "application/vnd.github.v3+json")
                    .post(body).tag(this).build();
        } else {
            request = new Request.Builder().url(urlBean.getUrl())
                    .header("User-Agent", "OkHttp Headers.java")
                    .addHeader("Accept", "application/json; q=0.5")
                    .addHeader("Accept", "application/vnd.github.v3+json")
                    .post(body).tag(this).build();
        }
        return request;
    }

    /**
     * 请求失败统一处理
     *
     * @param description 接口描述
     */
    private void requestFailure(Context context, String description, Exception e) {
        Log.i(TAG, "onFailure: ======" + e.toString());
        MessageBox.show(context, description + "=" + e.getMessage());
    }

    /**
     * 响应失败统处理
     *
     * @param result
     */
    private void responseFailure(Context context, String description, String result) {
        MessageBox.show(context, description + "=" + result);
    }
}
